package com.ssky.bean.validator.core.checker;

import com.ssky.bean.validator.core.IValidatorContext;
import com.ssky.bean.validator.core.ValueExpArithmeticExeHandler;
import com.ssky.bean.validator.core.exception.VldException;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;

/**
 * *<li/> 针对String、Number类型实例对象校验；其他类型不允许使用该规则。
 *
 * @param <V>
 * @param <L>
 * @param <B>
 * @Author: ssky
 * @Date: 2021/07/31
 * @Description:
 */
public class NumberLimitChecker<V, L, B>
        extends AbstractChecker<V, L, B> {
    //开始操作数 ---支持取值表达式，算术表达式
    private String beginOprand;

    //开始操作符
    private String beginOperator;

    //结束操作数 ---支持取值表达式，算术表达式
    private String endOprand;

    //结束操作符
    private String endOperator;

    private boolean hasBegin = false;
    private boolean hasEnd = false;
    private boolean isEquals = false;

    private ValueExpArithmeticExeHandler beginOprandExpHandler;

    private ValueExpArithmeticExeHandler endOprandExpHandler;

    @Override
    public void initz() throws Exception {

        if (StringUtils.isBlank(beginOprand) && StringUtils.isBlank(endOprand)) {
            throw new VldException("Rule:" + getId() + " Config Error : The \"beginOprand\" or  \"endOprand\" property value  cant't be empty at the same time !");
        }

        if (!StringUtils.isBlank(beginOprand)) {
            if (StringUtils.isBlank(beginOperator)) {
                throw new VldException("Rule:" + getId() + " Config Error : The \"beginOprand\" and  \"beginOperator\" must be used together !");
            }
            this.beginOprand = this.beginOprand.trim();
            this.beginOperator = this.beginOperator.trim();
            if (!this.beginOperator.equals(">") && !this.beginOperator.equals(">=")) {
                throw new VldException("Rule:" + getId() + " Config Error : The  \"beginOperator\" format error ' >, >= ' one of them !");
            }
            this.hasBegin = true;
            this.beginOprandExpHandler = new ValueExpArithmeticExeHandler(this.fieldValueGetHandler, this.beginOprand);
        } else {
            this.hasBegin = false;
        }

        if (!StringUtils.isBlank(endOprand)) {
            if (StringUtils.isBlank(endOperator)) {
                throw new VldException("Rule:" + getId() + " Config Error : The \"endOprand\" and  \"endOperator\" must be used together  !");
            }
            this.endOprand = this.endOprand.trim();
            this.endOperator = this.endOperator.trim();
            if (!this.endOperator.equals("<") && !this.endOperator.equals("<=")) {
                throw new VldException("Rule:" + getId() + " Config Error : The  \"endOperator\" format error ' <, <= ' one of them !");
            }
            this.hasEnd = true;
            this.endOprandExpHandler = new ValueExpArithmeticExeHandler(this.fieldValueGetHandler, this.endOprand);
        } else {
            this.hasEnd = false;
        }

        if (">=".equals(this.beginOperator) && "<=".equals(this.endOperator) && this.beginOprand.equals(this.endOprand)) {
            this.isEquals = true;
        }
    }

    /**
     * 具体规则执行器
     *
     * @param v   规则校验的当前值
     * @param l   当前值作为属性的所在对象
     * @param b   当前值所在的顶级javaBean对象
     * @param ctx 上下文（针对具体规则的实现要求，可基于接口IValidatorContext扩展）
     * @return 校验通过返回true, 不通过返回false
     */
    @Override
    public boolean process(V v, L l, B b, IValidatorContext ctx) {
        if (v == null || StringUtils.isBlank(v.toString())) {
            return true;
        }

        if (getField().getClassType() != v.getClass()) {
            throw new VldException("RuleId=" + getId() + " error ; The field type(" + v.getClass().getName() + ") is not match with config(" + getField().getClassType() + ")!");
        }

        BigDecimal vTmp = null;
        if (BigDecimal.class != getField().getClassType()) {
            vTmp = new BigDecimal(v.toString());
        } else {
            vTmp = (BigDecimal) v;
        }

        boolean rstBegin = false;
        boolean rstEnd = false;

        BigDecimal valueBegin = null;
        BigDecimal valueEnd = null;

        if (this.isEquals) {
            valueBegin = beginOprandExpHandler.exe(v, l, b, ctx);
            if (valueBegin == null) {
                return false;
            }
            int iStart = vTmp.compareTo(valueBegin);
            if (iStart == 0) {
                return true;
            }
            return false;
        }

        if (this.hasBegin) {
            valueBegin = beginOprandExpHandler.exe(v, l, b, ctx);
            if (valueBegin == null) {
                return false;
            }
            int iStart = vTmp.compareTo(valueBegin);
            if (this.beginOperator.equals(">")) {
                if (iStart <= 0) {
                    return false;
                }
            } else if (iStart < 0) {
                return false;
            }
        }

        if (this.hasEnd) {
            valueEnd = endOprandExpHandler.exe(v, l, b, ctx);

            if (valueEnd == null) {
                return false;
            }
            int iEnd = vTmp.compareTo(valueEnd);
            if (this.endOperator.equals("<")) {
                if (iEnd >= 0) {
                    return false;
                }
            } else if (iEnd > 0) {
                return false;
            }
        }
        return true;
    }

    public String getBeginOprand() {
        return this.beginOprand;
    }

    public void setBeginOprand(String beginOprand) {
        this.beginOprand = beginOprand;
    }

    public String getBeginOperator() {
        return this.beginOperator;
    }

    public void setBeginOperator(String beginOperator) {
        this.beginOperator = beginOperator;
    }

    public String getEndOprand() {
        return this.endOprand;
    }

    public void setEndOprand(String endOprand) {
        this.endOprand = endOprand;
    }

    public String getEndOperator() {
        return this.endOperator;
    }

    public void setEndOperator(String endOperator) {
        this.endOperator = endOperator;
    }
}